#include "itemModel.h"
#include <QtXml/QDomDocument>
#include <QtCore/QModelIndex>
#include <QtCore/QVariant>
#include <QtCore/QStringList>
#include <QtCore/QFile>
#include <QtCore/QMimeData>
#include <QtCore/QDataStream>
#include <QtCore/QTextStream>

bool loadXmlFile(const QString & xmlFile, QDomDocument & doc);

Qt::ItemFlags ItemModel::flags(const QModelIndex &index) const
{
	if (!index.isValid())
		return 0;

	Item *item = static_cast<Item*>(index.internalPointer());
	AdapterDElement *adapter = dynamic_cast<AdapterDElement*>(item);

	if (adapter)
		return Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
	else
		return 0;
}

QVariant ItemModel::data(const QModelIndex &index, int role) const
{
	if (!index.isValid())
		return QVariant();

	Item *item = static_cast<Item*>(index.internalPointer());
	switch(role) {
	case Qt::DisplayRole:
		return item->displayName();
	case Qt::DecorationRole:
		return item->getPixmap();
	case Qt::ToolTipRole:
		return item->toolTip();
	case Qt::StatusTipRole:
		return item->statusTip();
	case Qt::WhatsThisRole:
		return item->whatsThis();
	default:
		return QVariant();
	}
}

//QVariant ItemModel::headerData(int section, Qt::Orientation orientation, int role) const
//{
//	return QVariant();
//}

QModelIndex ItemModel::index(int row, int column, const QModelIndex &parent) const
{
	if (!hasIndex(row, column, parent))
		return QModelIndex();

	Item *parentItem;

	if (!parent.isValid())
		parentItem = mRoot;
	else
		parentItem = static_cast<Item*>(parent.internalPointer());

	Item *childItem = parentItem->child(row);
	if (childItem)
		return createIndex(row, column, childItem);
	else
		return QModelIndex();
}

QModelIndex ItemModel::parent(const QModelIndex &child) const
{
	if (!child.isValid())
		return QModelIndex();

	Item *childItem = static_cast<Item*>(child.internalPointer());
	Item *parentItem = childItem->parent();

	if (!parentItem || parentItem == mRoot)
		return QModelIndex();

	return createIndex(parentItem->row(), 0, parentItem);
}

int ItemModel::columnCount(const QModelIndex &/*parent*/) const
{
	return 1;
}

int ItemModel::rowCount(const QModelIndex &parent) const
{
	Item *parentItem;

	if (!parent.isValid())
		parentItem = mRoot;
	else
		parentItem = static_cast<Item*>(parent.internalPointer());

	return parentItem->childCount();
} 

//Initialize the Element Model data.
bool ItemModel::loadData(const QString& xmlFile)
{
	QDomDocument doc;
	if (!loadXmlFile(xmlFile,doc))
		return false;

	QDomElement e = doc.documentElement();
	loadChildData(e, mRoot);
	return true;	
}

bool ItemModel::loadChildData(const QDomElement& e, Item* father)
{
	//deep first construction the data hierarchy
	//incremental interpretation
	QDomElement subElement = e.firstChildElement();
	while ( !subElement.isNull()) {
		if ( subElement.nodeName() == "list") {
			ListItem* item = new ListItem();
			item->load(subElement);
			father->appendChild( item );

			//recursion
			if (!loadChildData(subElement, item)) {
				QString xmlSeg;
				QTextStream text(&xmlSeg);
				text << e;
				qWarning("There are errors in interpreting QDomElement '%s'", qPrintable(xmlSeg));
				return false;
			}
		}else {
			AdapterDElement* adapter = new AdapterDElement();
			if (adapter->load(subElement)) father->appendChild(adapter);
		}

		subElement = subElement.nextSiblingElement();
	}
	return true;
}

QStringList ItemModel::mimeTypes() const
{
	QStringList types(dragDataType);
	types << QString("text/plain"); //want to be seen in text, but not be implemented just
	return types;
}


//just be called on leaf items: AdapterDElement'DElement
QMimeData* ItemModel::mimeData(const QModelIndexList &indexes) const
{
	QMimeData *data = new QMimeData();

	QByteArray bytes;
	QDataStream stream(&bytes, QIODevice::WriteOnly);	

	//provide data for QDrag which is provided by Qt Framework
	foreach (QModelIndex it, indexes)
	{
		Item *item = static_cast<Item*>( it.internalPointer() );
	    AdapterDElement *ada = dynamic_cast<AdapterDElement*>(item);
		DElement* de = ada->getDElement();
		stream << de->kind() << de->className();
	}

	data->setData( dragDataType, bytes);
	
	return data;
}